package websocketgulu.demo.socket;


import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import websocketgulu.demo.Utils.BeanUtils;
import websocketgulu.demo.Utils.DataToWav;
import websocketgulu.demo.Utils.HexEcodeUtil;
import websocketgulu.demo.Utils.TestPathUtils;
import websocketgulu.demo.service.Impl.Mp3DataServiceImpl;
import websocketgulu.demo.service.Mp3DataService;
import websocketgulu.demo.websocket.showDiagramWebSocket;

import java.io.*;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.UUID;

/**
 * 创建socket任务处理器 SocketHandler,里面封装读写数据,销毁链接,等方法.
 */

@Slf4j
public class SocketHandler {

    static final String dateFormatStr = "yyyy-MM-dd HH:mm:ss";
    static final String dateFormatStr1 = "yyyy-MM-dd-HH-mm-ss";
    static final String connectedMessage = "conntected!";
    static final String dateCharSetName = "utf-8";



    /**
     * 将连接的Socket注册到Socket池中
     *
     * @param socket 一个socket
     * @return
     */
    public static ClientSocket register(Socket socket) {
        ClientSocket clientSocket = new ClientSocket();
        clientSocket.setSocket(socket);
        try {

            System.out.println("新建立了一个连接");
            clientSocket.setInputStream(new DataInputStream(socket.getInputStream()));
            clientSocket.setOutputStream(new DataOutputStream(socket.getOutputStream()));

            // 为什么我们第一次得数据收不到，因为我么把第一次的数据当成了key,后面会在这边加上验证环节
//            byte[] bytes = new byte[1024];
//            clientSocket.getInputStream().read(bytes);
//            clientSocket.setKey(new String(bytes, "utf-8"));
            String key = UUID.randomUUID().toString().replaceAll("-", "");
            clientSocket.setKey(key);

            SocketPool.add(clientSocket);
            // 测试发送
            SocketHandler.sendMessage(clientSocket, connectedMessage);
            return clientSocket;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 向指定客户端发送信息
     *
     * @param clientSocket
     * @param message
     */

    public static void sendMessage(ClientSocket clientSocket, String message) {
        try {
            log.info("发送消息到客户端  : >>>>>" + message);
            clientSocket.getOutputStream().write(message.getBytes(dateCharSetName));
            //clientSocket.getOutputStream().writeUTF(message);
        } catch (IOException e) {
            log.error("发送信息异常：{}", e);
            close(clientSocket);
        }
    }


    /**
     * 一帧是1055个字节， 从30：1053是数据，我们选取16帧为一个文件.
     * 获取指定客户端的上传信息
     *
     * @param clientSocket
     * @return
     */
    public static void onMessage(ClientSocket clientSocket) {
        byte[] msgByte = new byte[1055];
        byte[] data = new byte[1024];
        byte[] byteSerial = new byte[4];               // 表示序号的字节数组
        int flag = 0;
        StringBuilder hexSerial = new StringBuilder();
        int serial = 0;
        String collection_time = "";
        String end_time = "";
        String single_Array_Data = "";
        String all_data = "";  SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatStr);
        // 这个格式是给文件名使用得

        SimpleDateFormat dateFormat1 = new SimpleDateFormat(dateFormatStr1);

        try {
            FileOutputStream fos = null;
            String filename = null;
            Mp3DataService dataService = (Mp3DataService) BeanUtils.getBean("mp3DataServiceImpl");

            // 循环写入每一帧的数据
            while (true) {

                if (clientSocket.getInputStream().available() > 0) {

                    // 默认16*60帧一个音频，时长1分钟
                    if (flag == 0) {
                        Date date = new Date();
                        collection_time = dateFormat.format(Long.valueOf(date.getTime()));
                        end_time = dateFormat.format(new Date(date.getTime() + 1000));
                        filename = dateFormat1.format(Long.valueOf(date.getTime())) + ".pcm";
//                        fos = DataToWav.writeWavHeader( TestPathUtils.getPath() + filename );
                        fos = new FileOutputStream(TestPathUtils.getPath() + filename);
                    }
                    // 接收数据，打印帧号，写入数据
                    clientSocket.getInputStream().read(msgByte); // 流在这里
                    System.arraycopy(msgByte, 4, byteSerial, 0, 4);
                    for (byte b : byteSerial)
                        hexSerial.append(HexEcodeUtil.ByteArrayToAsc(b));
                    serial = Integer.parseInt(String.valueOf(hexSerial), 16);
                    hexSerial.setLength(0);
                    System.out.println("number of serial : " + serial);

                    // 取出数据部分，写入文件
                    System.arraycopy(msgByte, 30, data, 0, 1024);

                    DataToWav.WriteWaveData(TestPathUtils.getPath() + filename, data, fos);

                    //***
                    ByteBuffer byteBuffer = ByteBuffer.wrap(data);

                    // 这里能不能直接发送pcm，然后前端接收
                    if (showDiagramWebSocket.serviceOn())
                        showDiagramWebSocket.sendBinary(byteBuffer);
                    flag++;

                    // 已经解析完了一秒钟的数据
                    if (flag == 16) {
                        dataService.ParseAndSend(collection_time, end_time, filename);
                        fos.close();
                        flag = 0;
                    }
                } // end if

            }   // end while
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Exception");
        } finally {
            System.out.println("要退出了");
        }
    }


    /**
     * 指定Socket资源回收
     *
     * @param clientSocket
     */
    public static void close(ClientSocket clientSocket) {
        log.info("进行资源回收");
        if (clientSocket != null) {
            log.info("开始回收socket相关资源，其Key为{}");
            SocketPool.remove(clientSocket.getKey());

            Socket socket = clientSocket.getSocket();
            try {
                socket.shutdownInput();
                socket.shutdownOutput();
            } catch (IOException e) {
                log.error("关闭输入输出流异常，{}", e);
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    log.error("关闭socket异常{}", e);
                }
            }
        }
    }


    /**
     * 发送数据包，判断数据连接状态
     *
     * @param clientSocket
     * @return
     */
    public static boolean isSocketClosed(ClientSocket clientSocket) {
        try {
            clientSocket.getSocket().sendUrgentData(1);
            return false;
        } catch (IOException e) {
            return true;
        }
    }
}